arules caret factoextra GGally hexbin plotly proxy muestreo seriación tidyr tidyverse
Este ejercicio proporciona ejemplos para limpiar y preparar datos para la minería de datos.
Usaremos un conjunto de datos de juguete que viene con el conjunto de datos de iris de R. Fisher que proporciona las medidas en centímetros de las variables longitud del sépalo, longitud del sépalo, longitud del pétalo y anchura del pétalo para 150 flores. El conjunto de datos contiene 50 flores de cada una de las 3 especies de iris. Las especies son Iris Setosa, Iris Versicolor e Iris Virginica. Para más detalles ver ? iris.
Cargamos el conjunto de datos del iris. Los conjuntos de datos que vienen con paquetes R o R se pueden cargar con data(). El formato estándar para datos en R es un data.frame. Convertimos el data.frame en un tibble tidyverse.
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.2 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.2 ✔ tibble 3.2.1
## ✔ lubridate 1.9.2 ✔ tidyr 1.3.0
## ✔ purrr 1.0.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
data(iris)
iris <- as_tibble(iris)
iris
## # A tibble: 150 × 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fct>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
## 7 4.6 3.4 1.4 0.3 setosa
## 8 5 3.4 1.5 0.2 setosa
## 9 4.4 2.9 1.4 0.2 setosa
## 10 4.9 3.1 1.5 0.1 setosa
## # ℹ 140 more rows
Vemos que los datos contienen 150 filas (flores) y 5 características. Tibbles solo muestra las primeras filas y no muestra todas las características, si no se ajustan al ancho de la pantalla. Podemos llamar a imprimir y definir cuántas filas mostrar usando el parámetro n y forzar a imprimir para mostrar todas las características cambiando el ancho a infinito: inf.
print(iris, n = 3, width = Inf)
## # A tibble: 150 × 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fct>
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## # ℹ 147 more rows
Evaluar la calidad de los datos disponibles es crucial antes de comenzar a utilizarlos. Comience con estadísticas de resumen para cada columna para identificar valores atípicos y faltantes.
summary(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## Species
## setosa :50
## versicolor:50
## virginica :50
##
##
##
También puede resumir columnas específicas usando una función estadística como mean().
iris %>% summarize_if(is.numeric, mean)
## # A tibble: 1 × 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <dbl> <dbl> <dbl>
## 1 5.84 3.06 3.76 1.20
Para encontrar valores atípicos o problemas de datos, debe buscar valores muy pequeños (a menudo, una gran cantidad sospechosa de ceros) usando min y valores extremadamente grandes usando max. La comparación de la mediana y la media nos dice si la distribución es simétrica.
Un método visual para inspeccionar los datos es usar una matriz de diagrama de dispersión (aquí usamos ggpairs() del paquete GGally). En este gráfico, podemos identificar visualmente puntos de datos de ruido y valores atípicos (puntos que están lejos de la mayoría de los otros puntos).
library(GGally)
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
Un método visual para inspeccionar los datos es usar una matriz de diagrama de dispersión (aquí usamos ggpairs() del paquete GGally). En este gráfico, podemos identificar visualmente puntos de datos de ruido y valores atípicos (puntos que están lejos de la mayoría de los otros puntos).
ggpairs(iris, aes(color = Species))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Vea si puede detectar el único punto rojo que está lejos de todos los demás.
Muchos métodos de minería de datos requieren datos completos, es decir, los datos no pueden contener valores faltantes (NA). Para eliminar valores faltantes y duplicados (puntos de datos idénticos que pueden ser un error en los datos), a menudo hacemos esto:
clean.data <- iris %>% drop_na() %>% unique()
summary(clean.data)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## Min. :4.300 Min. :2.00 Min. :1.000 Min. :0.100 setosa :50
## 1st Qu.:5.100 1st Qu.:2.80 1st Qu.:1.600 1st Qu.:0.300 versicolor:50
## Median :5.800 Median :3.00 Median :4.300 Median :1.300 virginica :49
## Mean :5.844 Mean :3.06 Mean :3.749 Mean :1.195
## 3rd Qu.:6.400 3rd Qu.:3.30 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.40 Max. :6.900 Max. :2.500
Tenga en cuenta que un caso no único se ha ido dejando solo 149 flores. Los datos no contenían valores faltantes, pero si los tuvieran, también se habrían descartado. Por lo general, debería dedicar mucho más tiempo a la limpieza de datos.
Los datos a menudo contienen grupos y queremos comparar estos grupos. Agrupamos el conjunto de datos de iris por especie y luego calculamos una estadística de resumen para cada grupo.
iris %>% group_by(Species) %>% summarize_all(mean)
## # A tibble: 3 × 5
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 setosa 5.01 3.43 1.46 0.246
## 2 versicolor 5.94 2.77 4.26 1.33
## 3 virginica 6.59 2.97 5.55 2.03
iris %>% group_by(Species) %>% summarize_all(median)
## # A tibble: 3 × 5
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 setosa 5 3.4 1.5 0.2
## 2 versicolor 5.9 2.8 4.35 1.3
## 3 virginica 6.5 3 5.55 2
Usando esta información, podemos comparar cómo las características difieren entre grupos.
El muestreo se usa a menudo en la minería de datos para reducir el tamaño del conjunto de datos antes del modelado o la visualización.
La función de muestra integrada puede tomar muestras de un vector. Aquí tomamos muestras con reemplazo.
sample(c("A", "B", "C"), size = 10, replace = TRUE)
## [1] "B" "A" "C" "A" "B" "C" "C" "B" "A" "A"
A menudo queremos muestrear filas de un conjunto de datos. Esto se puede hacer muestreando sin reemplazo de un vector con índices de fila (usando las funciones seq() y nrow()). Luego, el vector de muestra se usa para dividir las filas del conjunto de datos.
take <- sample(seq(nrow(iris)), size = 15)
take
## [1] 100 17 28 22 63 132 118 104 101 29 12 41 5 145 112
iris[take, ]
## # A tibble: 15 × 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fct>
## 1 5.7 2.8 4.1 1.3 versicolor
## 2 5.4 3.9 1.3 0.4 setosa
## 3 5.2 3.5 1.5 0.2 setosa
## 4 5.1 3.7 1.5 0.4 setosa
## 5 6 2.2 4 1 versicolor
## 6 7.9 3.8 6.4 2 virginica
## 7 7.7 3.8 6.7 2.2 virginica
## 8 6.3 2.9 5.6 1.8 virginica
## 9 6.3 3.3 6 2.5 virginica
## 10 5.2 3.4 1.4 0.2 setosa
## 11 4.8 3.4 1.6 0.2 setosa
## 12 5 3.5 1.3 0.3 setosa
## 13 5 3.6 1.4 0.2 setosa
## 14 6.7 3.3 5.7 2.5 virginica
## 15 6.4 2.7 5.3 1.9 virginica
dplyr de tidyverse nos permite muestrear filas de tibbles directamente usando slice_sample(). Configuré la semilla del generador de números aleatorios para que los resultados fueran reproducibles.
set.seed(1000)
s <- iris %>% slice_sample(n = 15)
ggpairs(s, aes(color = Species))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
El muestreo estratificado es un método de muestreo de una población que se puede dividir en subpoblaciones, mientras se controlan las proporciones de la subpoblación en la muestra resultante.
A continuación, las subpoblaciones son los diferentes tipos de especies y queremos asegurarnos de muestrear el mismo número (5) de flores de cada una. El muestreo de biblioteca proporciona una función para el muestreo estratificado. La columna ID_unit en el data.frame resultante contiene los números de fila de las filas muestreadas. Podemos usar slice() de dplyr para seleccionar las filas muestreadas.
library(sampling)
id2 <- strata(iris, stratanames = "Species", size = c(5,5,5), method = "srswor")
id2
## Species ID_unit Prob Stratum
## 7 setosa 7 0.1 1
## 9 setosa 9 0.1 1
## 10 setosa 10 0.1 1
## 24 setosa 24 0.1 1
## 48 setosa 48 0.1 1
## 58 versicolor 58 0.1 2
## 62 versicolor 62 0.1 2
## 74 versicolor 74 0.1 2
## 78 versicolor 78 0.1 2
## 99 versicolor 99 0.1 2
## 106 virginica 106 0.1 3
## 107 virginica 107 0.1 3
## 127 virginica 127 0.1 3
## 135 virginica 135 0.1 3
## 145 virginica 145 0.1 3
s2 <- iris %>% slice(id2$ID_unit)
ggpairs(s2, aes(color = Species))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
PCA calcula los componentes principales (un conjunto de nuevos vectores de base ortonormales en el espacio de datos) a partir de puntos de datos tales que el primer componente principal explica la mayor variabilidad en los datos, el segundo la siguiente y así sucesivamente. En el análisis de datos, PCA se utiliza para proyectar puntos de datos de alta dimensión en los primeros componentes principales (generalmente dos) para su visualización como un gráfico de dispersión y como preprocesamiento para el modelado (p. ej., antes del agrupamiento de k-medias). Los puntos que están más juntos en el espacio original de alta dimensión tienden a estarlo también cuando se proyectan en el espacio de menor dimensión.
Podemos usar una gráfica tridimensional interactiva (del paquete plotly) para observar tres de las cuatro dimensiones del conjunto de datos del iris. Tenga en cuenta que es difícil visualizar más de 3 dimensiones.
# library(plotly) # No cargo el paquete porque su espacio de nombres choca con select en dplyr.
plotly::plot_ly(iris, x = ~Sepal.Length, y = ~Petal.Length, z = ~Sepal.Width,
size = ~Petal.Width, color = ~Species, type="scatter3d")
## No scatter3d mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
## Warning: `line.width` does not currently support multiple values.
## Warning: `line.width` does not currently support multiple values.
## Warning: `line.width` does not currently support multiple values.
Los componentes principales se pueden calcular a partir de una matriz utilizando la función prcomp(). Seleccionamos todas las columnas numéricas (deseleccionando la columna de especies) y convertimos el tibble en una matriz antes del cálculo.
pc <- iris %>% select(-Species) %>% as.matrix() %>% prcomp()
summary(pc)
## Importance of components:
## PC1 PC2 PC3 PC4
## Standard deviation 2.0563 0.49262 0.2797 0.15439
## Proportion of Variance 0.9246 0.05307 0.0171 0.00521
## Cumulative Proportion 0.9246 0.97769 0.9948 1.00000
La importancia de cada componente principal también se puede ver usando un diagrama de sedimentación. La función de trazado para el resultado de la función prcomp visualiza cuánta variabilidad en los datos se explica por cada componente principal adicional.
plot(pc, type = "line")
Tenga en cuenta que el primer componente principal (PC1) explica la mayor parte de la variabilidad en el conjunto de datos del iris.
Para averiguar qué información está almacenada en el objeto pc, podemos inspeccionar el objeto sin procesar (estructura de visualización).
str(pc)
## List of 5
## $ sdev : num [1:4] 2.056 0.493 0.28 0.154
## $ rotation: num [1:4, 1:4] 0.3614 -0.0845 0.8567 0.3583 -0.6566 ...
## ..- attr(*, "dimnames")=List of 2
## .. ..$ : chr [1:4] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
## .. ..$ : chr [1:4] "PC1" "PC2" "PC3" "PC4"
## $ center : Named num [1:4] 5.84 3.06 3.76 1.2
## ..- attr(*, "names")= chr [1:4] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
## $ scale : logi FALSE
## $ x : num [1:150, 1:4] -2.68 -2.71 -2.89 -2.75 -2.73 ...
## ..- attr(*, "dimnames")=List of 2
## .. ..$ : NULL
## .. ..$ : chr [1:4] "PC1" "PC2" "PC3" "PC4"
## - attr(*, "class")= chr "prcomp"
El objeto pc (como la mayoría de los objetos en R) es una lista con un atributo de clase. El elemento de lista x contiene los puntos de datos proyectados sobre los componentes principales. Podemos convertir la matriz en un tibble y volver a agregar la columna de especies del conjunto de datos original (ya que las filas están en el mismo orden), y luego mostrar los datos proyectados en los dos primeros componentes principales.
iris_projected <- as_tibble(pc$x) %>% add_column(Species = iris$Species)
ggplot(iris_projected, aes(x = PC1, y = PC2, color = Species)) +
geom_point()
Las flores que se muestran muy juntas en esta proyección también lo están en el espacio original de 4 dimensiones. Dado que el primer componente principal representa la mayor parte de la variabilidad, también podemos mostrar los datos proyectados solo en PC1.
ggplot(iris_projected,
aes(x = PC1, y = 0, color = Species)) +
geom_point() +
scale_y_continuous(expand=c(0,0)) +
theme(axis.text.y = element_blank(),
axis.title.y = element_blank()
)
Vemos que podemos separar perfectamente la especie Setosa usando solo el primer componente principal. Las otras dos especies son más difíciles de separar.
Un gráfico de los datos proyectados con los ejes originales agregados como flechas se denomina bigráfico. Si las flechas (ejes originales) se alinean aproximadamente con los ejes de la proyección, entonces están correlacionadas (dependen linealmente).
library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
fviz_pca(pc)
También podemos mostrar solo los ejes antiguos y nuevos.
fviz_pca_var(pc)
Vemos que Petal.Width y Petal.Length apuntan en la misma dirección, lo que indica que están altamente correlacionados. También están aproximadamente alineados con PC1 (llamado Dim1 en la gráfica), lo que significa que PC1 representa la mayor parte de la variabilidad de estas dos variables. Sepal.Width está casi alineado con el eje y y, por lo tanto, está representado por PC2 (Dim2). Petal.Width/Petal.Length y Sepal.Width están casi a 90 grados, lo que indica que casi no están correlacionados. Sepal.Length se correlaciona con todas las demás variables y se representa tanto por PC1 como por PC2 en la proyección.
Existen otros métodos para incrustar datos de dimensiones superiores en un espacio de dimensiones inferiores. Un método popular para proyectar datos en dimensiones más bajas para su visualización es la incrustación de vecinos estocásticos distribuidos en t (t-SNE) (t-distributed stochastic neighbor embedding (t-SNE))disponible en el paquete Rtsne.
MDS es similar a PCA. En lugar de puntos de datos, comienza con distancias por pares (es decir, una matriz de distancia) y produce un espacio donde se colocan los puntos para representar estas distancias lo mejor posible. Los ejes en este espacio se llaman componentes y son similares a los componentes principales en PCA.
Primero, calculamos una matriz de distancia (distancias euclidianas) del espacio 4-d del conjunto de datos del iris.
d <- iris %>% select(-Species) %>% dist()
Métrico (clásico) MDS intenta construir un espacio donde los puntos con distancias más bajas se colocan más cerca. Proyectamos los datos representados por una matriz de distancia en k = 2 dimensiones.
fit <- cmdscale(d, k = 2)
colnames(fit) <- c("comp1", "comp2")
fit <- as_tibble(fit) %>% add_column(Species = iris$Species)
ggplot(fit, aes(x = comp1, y = comp2, color = Species)) + geom_point()
La proyección resultante es similar (excepto por la rotación y la reflexión) al resultado de la proyección usando PCA.
El escalado multidimensional no paramétrico realiza MDS mientras relaja la necesidad de relaciones lineales. Los métodos están disponibles en el paquete MASS como funciones isoMDS() y sammon().
La selección de funciones es el proceso de identificar las funciones que se utilizan para crear un modelo. Hablaremos sobre la selección de características cuando discutamos los modelos de clasificación en el Capítulo 3 en
Selección de características y preparación de características
Algunos métodos de minería de datos requieren datos discretos. La discretización convierte características continuas en características discretas. Como ejemplo, discretizaremos la característica continua Petal.Width. Antes de realizar la discretización, debemos observar la distribución y ver si nos da una idea de cómo debemos agrupar los valores continuos en un conjunto de valores discretos. Un histograma visualiza la distribución de una única característica continua.
ggplot(iris, aes(x = Petal.Width)) + geom_histogram(binwidth = .2)
Los contenedores en el histograma representan una discretización utilizando un ancho de contenedor fijo. La función R cut() realiza una discretización de ancho de intervalo igual.
iris %>% pull(Sepal.Width) %>% cut(breaks = 3)
## [1] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (3.6,4.4] (2.8,3.6]
## [8] (2.8,3.6] (2.8,3.6] (2.8,3.6] (3.6,4.4] (2.8,3.6] (2.8,3.6] (2.8,3.6]
## [15] (3.6,4.4] (3.6,4.4] (3.6,4.4] (2.8,3.6] (3.6,4.4] (3.6,4.4] (2.8,3.6]
## [22] (3.6,4.4] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6]
## [29] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (3.6,4.4] (3.6,4.4] (2.8,3.6]
## [36] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2,2.8]
## [43] (2.8,3.6] (2.8,3.6] (3.6,4.4] (2.8,3.6] (3.6,4.4] (2.8,3.6] (3.6,4.4]
## [50] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2,2.8] (2,2.8] (2,2.8]
## [57] (2.8,3.6] (2,2.8] (2.8,3.6] (2,2.8] (2,2.8] (2.8,3.6] (2,2.8]
## [64] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2,2.8] (2,2.8] (2,2.8]
## [71] (2.8,3.6] (2,2.8] (2,2.8] (2,2.8] (2.8,3.6] (2.8,3.6] (2,2.8]
## [78] (2.8,3.6] (2.8,3.6] (2,2.8] (2,2.8] (2,2.8] (2,2.8] (2,2.8]
## [85] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2,2.8] (2.8,3.6] (2,2.8] (2,2.8]
## [92] (2.8,3.6] (2,2.8] (2,2.8] (2,2.8] (2.8,3.6] (2.8,3.6] (2.8,3.6]
## [99] (2,2.8] (2,2.8] (2.8,3.6] (2,2.8] (2.8,3.6] (2.8,3.6] (2.8,3.6]
## [106] (2.8,3.6] (2,2.8] (2.8,3.6] (2,2.8] (2.8,3.6] (2.8,3.6] (2,2.8]
## [113] (2.8,3.6] (2,2.8] (2,2.8] (2.8,3.6] (2.8,3.6] (3.6,4.4] (2,2.8]
## [120] (2,2.8] (2.8,3.6] (2,2.8] (2,2.8] (2,2.8] (2.8,3.6] (2.8,3.6]
## [127] (2,2.8] (2.8,3.6] (2,2.8] (2.8,3.6] (2,2.8] (3.6,4.4] (2,2.8]
## [134] (2,2.8] (2,2.8] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2.8,3.6]
## [141] (2.8,3.6] (2.8,3.6] (2,2.8] (2.8,3.6] (2.8,3.6] (2.8,3.6] (2,2.8]
## [148] (2.8,3.6] (2.8,3.6] (2.8,3.6]
## Levels: (2,2.8] (2.8,3.6] (3.6,4.4]
Otros métodos de discretización incluyen la discretización de igual frecuencia o el uso de agrupamiento de k-medias. Estos métodos son implementados por varios paquetes de R. Usamos aquí la implementación en el paquete arules y visualizamos los resultados como histogramas con líneas azules para separar los intervalos asignados a cada valor discreto.
library(arules)
## Loading required package: Matrix
##
## Attaching package: 'Matrix'
## The following objects are masked from 'package:tidyr':
##
## expand, pack, unpack
##
## Attaching package: 'arules'
## The following object is masked from 'package:dplyr':
##
## recode
## The following objects are masked from 'package:base':
##
## abbreviate, write
iris %>% pull(Petal.Width) %>% discretize(method = "interval", breaks = 3)
## [1] [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9)
## [8] [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9)
## [15] [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9)
## [22] [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9)
## [29] [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9)
## [36] [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9)
## [43] [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9) [0.1,0.9)
## [50] [0.1,0.9) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7)
## [57] [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7)
## [64] [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7)
## [71] [1.7,2.5] [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7)
## [78] [1.7,2.5] [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7)
## [85] [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7)
## [92] [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7) [0.9,1.7)
## [99] [0.9,1.7) [0.9,1.7) [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5]
## [106] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5]
## [113] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5]
## [120] [0.9,1.7) [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5]
## [127] [1.7,2.5] [1.7,2.5] [1.7,2.5] [0.9,1.7) [1.7,2.5] [1.7,2.5] [1.7,2.5]
## [134] [0.9,1.7) [0.9,1.7) [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5]
## [141] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5] [1.7,2.5]
## [148] [1.7,2.5] [1.7,2.5] [1.7,2.5]
## attr(,"discretized:breaks")
## [1] 0.1 0.9 1.7 2.5
## attr(,"discretized:method")
## [1] interval
## Levels: [0.1,0.9) [0.9,1.7) [1.7,2.5]
iris %>% pull(Petal.Width) %>% discretize(method = "frequency", breaks = 3)
## [1] [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867)
## [7] [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867)
## [13] [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867)
## [19] [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867)
## [25] [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867)
## [31] [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867)
## [37] [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867)
## [43] [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867) [0.1,0.867)
## [49] [0.1,0.867) [0.1,0.867) [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6)
## [55] [0.867,1.6) [0.867,1.6) [1.6,2.5] [0.867,1.6) [0.867,1.6) [0.867,1.6)
## [61] [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6)
## [67] [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [1.6,2.5] [0.867,1.6)
## [73] [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [1.6,2.5]
## [79] [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [1.6,2.5]
## [85] [0.867,1.6) [1.6,2.5] [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6)
## [91] [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6)
## [97] [0.867,1.6) [0.867,1.6) [0.867,1.6) [0.867,1.6) [1.6,2.5] [1.6,2.5]
## [103] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5]
## [109] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5]
## [115] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [0.867,1.6)
## [121] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5]
## [127] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5]
## [133] [1.6,2.5] [0.867,1.6) [0.867,1.6) [1.6,2.5] [1.6,2.5] [1.6,2.5]
## [139] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5]
## [145] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5] [1.6,2.5]
## attr(,"discretized:breaks")
## [1] 0.1000000 0.8666667 1.6000000 2.5000000
## attr(,"discretized:method")
## [1] frequency
## Levels: [0.1,0.867) [0.867,1.6) [1.6,2.5]
iris %>% pull(Petal.Width) %>% discretize(method = "cluster", breaks = 3)
## [1] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [6] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [11] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [16] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [21] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [26] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [31] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [36] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [41] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [46] [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792) [0.1,0.792)
## [51] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [56] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [61] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [66] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [71] [1.71,2.5] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [76] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [81] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [86] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [91] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [96] [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71) [0.792,1.71)
## [101] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5]
## [106] [1.71,2.5] [0.792,1.71) [1.71,2.5] [1.71,2.5] [1.71,2.5]
## [111] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5]
## [116] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5] [0.792,1.71)
## [121] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5]
## [126] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5] [0.792,1.71)
## [131] [1.71,2.5] [1.71,2.5] [1.71,2.5] [0.792,1.71) [0.792,1.71)
## [136] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5]
## [141] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5]
## [146] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5] [1.71,2.5]
## attr(,"discretized:breaks")
## [1] 0.1000000 0.7915185 1.7054750 2.5000000
## attr(,"discretized:method")
## [1] cluster
## Levels: [0.1,0.792) [0.792,1.71) [1.71,2.5]
ggplot(iris, aes(Petal.Width)) + geom_histogram(binwidth = .2) +
geom_vline(xintercept =
iris %>% pull(Petal.Width) %>% discretize(method = "interval", breaks = 3, onlycuts = TRUE),
color = "blue") +
labs(title = "Discretization: interval", subtitle = "Blue lines are boundaries")
ggplot(iris, aes(Petal.Width)) + geom_histogram(binwidth = .2) +
geom_vline(xintercept =
iris %>% pull(Petal.Width) %>% discretize(method = "frequency", breaks = 3, onlycuts = TRUE),
color = "blue") +
labs(title = "Discretization: frequency", subtitle = "Blue lines are boundaries")
ggplot(iris, aes(Petal.Width)) + geom_histogram(binwidth = .2) +
geom_vline(xintercept =
iris %>% pull(Petal.Width) %>% discretize(method = "cluster", breaks = 3, onlycuts = TRUE),
color = "blue") +
labs(title = "Discretization: cluster", subtitle = "Blue lines are boundaries")
El usuario debe decidir el número de intervalos y el método utilizado.
Estandarizar (escalar, normalizar) el rango de valores de características es importante para hacerlos comparables. El método más popular es convertir los valores de cada característica a puntajes z. restando la media (centrado) y dividiendo por la desviación estándar (escala). La característica estandarizada tendrá una media de cero y se mide en desviaciones estándar de la media. Los valores positivos indican cuántas desviaciones estándar el valor de la característica original estaba por encima del promedio. Los valores estandarizados negativos indican valores por debajo del promedio.
Nota: tidyverse actualmente no tiene una función de escala simple, así que creo una que proporciona un envoltorio para la función de escala estándar en R:
scale_numeric <- function(x) x %>% mutate_if(is.numeric, function(y) as.vector(scale(y)))
iris.scaled <- iris %>% scale_numeric()
iris.scaled
## # A tibble: 150 × 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <dbl> <dbl> <dbl> <dbl> <fct>
## 1 -0.898 1.02 -1.34 -1.31 setosa
## 2 -1.14 -0.132 -1.34 -1.31 setosa
## 3 -1.38 0.327 -1.39 -1.31 setosa
## 4 -1.50 0.0979 -1.28 -1.31 setosa
## 5 -1.02 1.25 -1.34 -1.31 setosa
## 6 -0.535 1.93 -1.17 -1.05 setosa
## 7 -1.50 0.786 -1.34 -1.18 setosa
## 8 -1.02 0.786 -1.28 -1.31 setosa
## 9 -1.74 -0.361 -1.34 -1.31 setosa
## 10 -1.14 0.0979 -1.28 -1.44 setosa
## # ℹ 140 more rows
summary(iris.scaled)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :-1.86378 Min. :-2.4258 Min. :-1.5623 Min. :-1.4422
## 1st Qu.:-0.89767 1st Qu.:-0.5904 1st Qu.:-1.2225 1st Qu.:-1.1799
## Median :-0.05233 Median :-0.1315 Median : 0.3354 Median : 0.1321
## Mean : 0.00000 Mean : 0.0000 Mean : 0.0000 Mean : 0.0000
## 3rd Qu.: 0.67225 3rd Qu.: 0.5567 3rd Qu.: 0.7602 3rd Qu.: 0.7880
## Max. : 2.48370 Max. : 3.0805 Max. : 1.7799 Max. : 1.7064
## Species
## setosa :50
## versicolor:50
## virginica :50
##
##
##
La característica estandarizada tiene una media de cero y la mayoría de los valores “normales” caerán en el rango −3, 3 (desviaciones estandar).
R almacena la proximidad como matrices de disimilitudes/distancias. Las similitudes se convierten primero en diferencias. Las distancias son simétricas, es decir, la distancia de A a B es la misma que la distancia de B a A. Por lo tanto, R almacena solo un triángulo (normalmente el triángulo inferior) de la matriz de distancia.
La distancia de Minkowsky es una familia de distancias métricas que incluye la distancia euclidiana y la de Manhattan. Para evitar que una entidad domine el cálculo de la distancia, normalmente se utilizan datos escalados. Seleccionamos las primeras 5 flores para este ejemplo.
iris_sample <- iris.scaled %>% select(-Species) %>% slice(1:5)
iris_sample
## # A tibble: 5 × 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <dbl> <dbl> <dbl>
## 1 -0.898 1.02 -1.34 -1.31
## 2 -1.14 -0.132 -1.34 -1.31
## 3 -1.38 0.327 -1.39 -1.31
## 4 -1.50 0.0979 -1.28 -1.31
## 5 -1.02 1.25 -1.34 -1.31
Se pueden calcular diferentes tipos de matrices de distancia de Minkowsky entre las primeras 5 flores usando dist().
dist(iris_sample, method = "euclidean")
## 1 2 3 4
## 2 1.1722914
## 3 0.8427840 0.5216255
## 4 1.0999999 0.4325508 0.2829432
## 5 0.2592702 1.3818560 0.9882608 1.2459861
dist(iris_sample, method = "manhattan")
## 1 2 3 4
## 2 1.3886674
## 3 1.2279853 0.7570306
## 4 1.5781768 0.6483657 0.4634868
## 5 0.3501915 1.4973323 1.3366502 1.6868417
dist(iris_sample, method = "maximum")
## 1 2 3 4
## 2 1.1471408
## 3 0.6882845 0.4588563
## 4 0.9177126 0.3622899 0.2294282
## 5 0.2294282 1.3765690 0.9177126 1.1471408
Los datos binarios se pueden codificar como 0 y 1 (numérico) o TRUE y FALSE (lógico).
b <- rbind(
c(0,0,0,1,1,1,1,0,0,1),
c(0,0,1,1,1,0,0,1,0,0)
)
b
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 0 0 0 1 1 1 1 0 0 1
## [2,] 0 0 1 1 1 0 0 1 0 0
b_logical <- apply(b, MARGIN = 2, as.logical)
b_logical
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] FALSE FALSE FALSE TRUE TRUE TRUE TRUE FALSE FALSE TRUE
## [2,] FALSE FALSE TRUE TRUE TRUE FALSE FALSE TRUE FALSE FALSE
La distancia de Hamming es el número de desajustes entre dos vectores binarios. Para datos 0-1, esto es equivalente a la distancia de Manhattan y también a la distancia euclidiana al cuadrado.
dist(b, method = "manhattan")
## 1
## 2 5
dist(b, method = "euclidean")^2
## 1
## 2 5
El índice de Jaccard es una medida de similitud que se enfoca en hacer coincidir 1s. R convierte la similitud en una disimilitud usando
dist(b, method = "binary")
## 1
## 2 0.7142857
La mayoría de las medidas de distancia funcionan solo con datos numéricos. A menudo, tenemos una mezcla de números y características nominales u ordinales como estos datos:
people <- tibble(
height = c( 160, 185, 170),
weight = c( 52, 90, 75),
sex = c( "female", "male", "male")
)
people
## # A tibble: 3 × 3
## height weight sex
## <dbl> <dbl> <chr>
## 1 160 52 female
## 2 185 90 male
## 3 170 75 male
Es importante que las características nominales se almacenen como
factores y no como caracteres (
people <- people %>% mutate_if(is.character, factor)
people
## # A tibble: 3 × 3
## height weight sex
## <dbl> <dbl> <fct>
## 1 160 52 female
## 2 185 90 male
## 3 170 75 male
El coeficiente de similitud de Gower funciona con datos mixtos al calcular la similitud adecuada para cada característica y luego agregarlos en una sola medida. El proxy del paquete implementa el coeficiente de Gower convertido en una distancia.
library(proxy)
##
## Attaching package: 'proxy'
## The following object is masked from 'package:Matrix':
##
## as.matrix
## The following objects are masked from 'package:stats':
##
## as.dist, dist
## The following object is masked from 'package:base':
##
## as.matrix
d_Gower <- dist(people, method = "Gower")
d_Gower
## 1 2
## 2 1.0000000
## 3 0.6684211 0.3315789
El cálculo del coeficiente de Gower escala implícitamente los datos porque calcula las distancias en cada entidad individualmente, por lo que no es necesario escalar los datos primero.
A veces, los métodos (por ejemplo, k-means) solo pueden usar la distancia euclidiana. En este caso, las características nominales se pueden convertir en variables ficticias 0-1. Después de escalar, la distancia euclidiana dará como resultado una medida de distancia utilizable.
Usamos el paquete caret para crear variables ficticias.
library(caret)
## Loading required package: lattice
##
## Attaching package: 'caret'
## The following object is masked from 'package:sampling':
##
## cluster
## The following object is masked from 'package:purrr':
##
## lift
data_dummy <- dummyVars(~., people) %>% predict(people)
data_dummy
## height weight sex.female sex.male
## 1 160 52 1 0
## 2 185 90 0 1
## 3 170 75 0 1
Tenga en cuenta que el sexo destacado ahora tiene dos columnas. Si queremos que la altura, el peso y el sexo tengan la misma influencia en la medida de la distancia, entonces debemos ponderar las columnas de sexo a la mitad después de scaling.
weight_matrix <- matrix(c(1, 1, 1/2, 1/2), ncol = 4, nrow = nrow(data_dummy), byrow = TRUE)
data_dummy_scaled <- scale(data_dummy) * weight_matrix
d_dummy <- dist(data_dummy_scaled)
d_dummy
## 1 2
## 2 3.064169
## 3 1.890931 1.426621
La distancia usando variables ficticias es consistente con la distancia de Gower. Sin embargo, tenga en cuenta que la distancia de Gower está escalada entre 0 y 1, mientras que la distancia euclidiana no lo está.
ggplot(tibble(d_dummy, d_Gower), aes(x = d_dummy, y = d_Gower)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE)
## Don't know how to automatically pick scale for object of type <dist>.
## Defaulting to continuous.
## Don't know how to automatically pick scale for object of type <dist>.
## Defaulting to continuous.
## `geom_smooth()` using formula = 'y ~ x'
El paquete proxy implementa una amplia gama de distancias.
library(proxy)
pr_DB$get_entry_names()
## [1] "Jaccard" "Kulczynski1" "Kulczynski2" "Mountford"
## [5] "Fager" "Russel" "simple matching" "Hamman"
## [9] "Faith" "Tanimoto" "Dice" "Phi"
## [13] "Stiles" "Michael" "Mozley" "Yule"
## [17] "Yule2" "Ochiai" "Simpson" "Braun-Blanquet"
## [21] "cosine" "angular" "eJaccard" "eDice"
## [25] "correlation" "Chi-squared" "Phi-squared" "Tschuprow"
## [29] "Cramer" "Pearson" "Gower" "Euclidean"
## [33] "Mahalanobis" "Bhjattacharyya" "Manhattan" "supremum"
## [37] "Minkowski" "Canberra" "Wave" "divergence"
## [41] "Kullback" "Bray" "Soergel" "Levenshtein"
## [45] "Podani" "Chord" "Geodesic" "Whittaker"
## [49] "Hellinger" "fJaccard"
Tenga en cuenta que cargar el paquete proxy reemplaza la función dist en R. Puede especificar qué función dist usar especificando el paquete en la llamada. Por ejemplo, stats::dist() llama a la función predeterminada en R (el paquete stats es parte de R) mientras que proxy::dist() llama a la versión en el proxy del paquete.
La correlación se puede utilizar para características escaladas de relación/intervalo. Por lo general, pensamos en el coeficiente de correlación de Pearson entre características (columnas).
cc <- iris %>% select(-Species) %>% cor()
cc
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Sepal.Length 1.0000000 -0.1175698 0.8717538 0.8179411
## Sepal.Width -0.1175698 1.0000000 -0.4284401 -0.3661259
## Petal.Length 0.8717538 -0.4284401 1.0000000 0.9628654
## Petal.Width 0.8179411 -0.3661259 0.9628654 1.0000000
cor calcula una matriz de correlación con correlaciones por pares entre entidades. Las matrices de correlación son simétricas, pero a diferencia de las distancias, se almacena toda la matriz.
La correlación entre Petal.Length y Petal.Width se puede visualizar mediante un diagrama de dispersión.
ggplot(iris, aes(Petal.Length, Petal.Width)) +
geom_point() +
geom_smooth(method = "lm")
## `geom_smooth()` using formula = 'y ~ x'
geom_smooth agrega una línea de regresión ajustando un modelo lineal (lm). La mayoría de los puntos están cerca de esta línea, lo que indica una fuerte dependencia lineal (es decir, alta correlación).
Podemos calcular correlaciones individuales especificando dos vectores.
with(iris, cor(Petal.Length, Petal.Width))
## [1] 0.9628654
Finalmente, podemos probar si una correlación es significativamente diferente de cero.
with(iris, cor.test(Petal.Length, Petal.Width))
##
## Pearson's product-moment correlation
##
## data: Petal.Length and Petal.Width
## t = 43.387, df = 148, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.9490525 0.9729853
## sample estimates:
## cor
## 0.9628654
Un valor p pequeño (menos de 0,05) indica que la correlación observada es significativamente diferente de cero. Esto también se puede ver por el hecho de que el intervalo de confianza del 95% no abarca el cero.
La correlación de rango se usa para características ordinales o si la correlación no es lineal. Para mostrar esto, primero convertimos las características continuas en el conjunto de datos de Iris en factores ordenados (ordinales) con tres niveles usando la función de corte.
iris_ord <- iris %>% mutate_if(is.numeric,
function(x) cut(x, 3, labels = c("short", "medium", "long"), ordered = TRUE))
iris_ord
## # A tibble: 150 × 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <ord> <ord> <ord> <ord> <fct>
## 1 short medium short short setosa
## 2 short medium short short setosa
## 3 short medium short short setosa
## 4 short medium short short setosa
## 5 short medium short short setosa
## 6 short long short short setosa
## 7 short medium short short setosa
## 8 short medium short short setosa
## 9 short medium short short setosa
## 10 short medium short short setosa
## # ℹ 140 more rows
summary(iris_ord)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## short :59 short :47 short :50 short :50 setosa :50
## medium:71 medium:88 medium:54 medium:54 versicolor:50
## long :20 long :15 long :46 long :46 virginica :50
iris_ord %>% pull(Sepal.Length)
## [1] short short short short short short short short short short
## [11] short short short short medium medium short short medium short
## [21] short short short short short short short short short short
## [31] short short short short short short short short short short
## [41] short short short short short short short short short short
## [51] long medium long short medium medium medium short medium short
## [61] short medium medium medium medium medium medium medium medium medium
## [71] medium medium medium medium medium medium long medium medium medium
## [81] short short medium medium short medium medium medium medium short
## [91] short medium medium short medium medium medium medium short medium
## [101] medium medium long medium medium long short long medium long
## [111] medium medium long medium medium medium medium long long medium
## [121] long medium long medium medium long medium medium medium long
## [131] long long medium medium medium long medium medium medium long
## [141] medium long medium long medium medium medium medium medium medium
## Levels: short < medium < long
Dos medidas para la correlación de rangos son Tau de Kendall y Rho de Spearman.
El coeficiente de correlación de rango Tau de Kendall mide la concordancia entre dos rangos (es decir, características ordinales).
iris_ord %>% select(-Species) %>% sapply(xtfrm) %>% cor(method = "kendall")
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Sepal.Length 1.0000000 -0.1437985 0.7418595 0.7295139
## Sepal.Width -0.1437985 1.0000000 -0.3298796 -0.3154474
## Petal.Length 0.7418595 -0.3298796 1.0000000 0.9198290
## Petal.Width 0.7295139 -0.3154474 0.9198290 1.0000000
La Rho de Spearman es igual a la correlación de Pearson entre los valores de rango de esas dos características.
iris_ord %>% select(-Species) %>% sapply(xtfrm) %>% cor(method = "spearman")
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Sepal.Length 1.0000000 -0.1569659 0.7937613 0.7843406
## Sepal.Width -0.1569659 1.0000000 -0.3662775 -0.3517262
## Petal.Length 0.7937613 -0.3662775 1.0000000 0.9399038
## Petal.Width 0.7843406 -0.3517262 0.9399038 1.0000000
La Rho de Spearman es mucho más rápida de calcular en grandes conjuntos de datos que la Tau de Kendall.
La comparación de los resultados de la correlación de rango con la correlación de Pearson en los datos originales muestra que son muy similares. Esto indica que la discretización de datos no da como resultado la pérdida de demasiada información.
iris %>% select(-Species) %>% cor()
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Sepal.Length 1.0000000 -0.1175698 0.8717538 0.8179411
## Sepal.Width -0.1175698 1.0000000 -0.4284401 -0.3661259
## Petal.Length 0.8717538 -0.4284401 1.0000000 0.9628654
## Petal.Width 0.8179411 -0.3661259 0.9628654 1.0000000
Las construcciones de estimación de densidad estiman la función de densidad de probabilidad (distribución) de una variable continua en función de los datos observados.
El simple hecho de graficar los datos usando puntos no es muy útil para una sola característica.
ggplot(iris, aes(x = Petal.Length, y = 0)) + geom_point()
Un histograma muestra más sobre la distribución al contar cuántos valores se encuentran dentro de un contenedor y visualizar los conteos como un gráfico de barras. Usamos geom_rug para colocar marcas para los puntos de datos originales en la parte inferior del histograma.
ggplot(iris, aes(x = Petal.Length)) +
geom_histogram() +
geom_rug(alpha = 1/2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Las distribuciones bidimensionales se pueden visualizar utilizando bins bidimensionales o bins hexagonales.
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_bin2d(bins = 10) +
geom_jitter(color = "red")
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_hex(bins = 10) +
geom_jitter(color = "red")
## Warning: Computation failed in `stat_binhex()`
## Caused by error in `compute_group()`:
## ! The package "hexbin" is required for `stat_binhex()`
La estimación de densidad kernel se utiliza para estimar la función de densidad de probabilidad (distribución) de una característica. Funciona reemplazando cada valor con una función kernel (a menudo una gaussiana) y luego sumándolos. El resultado es una función de densidad de probabilidad estimada que parece una versión suavizada del histograma. El ancho de banda (bw) del kernel controla la cantidad de suavizado.
library(tidyverse)
ggplot(iris, aes(Petal.Length)) +
geom_density(bw = .2) +
geom_rug(alpha = 1/2)
Las estimaciones de la densidad del núcleo también se pueden realizar en dos dimensiones.
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_density_2d_filled() +
geom_jitter()
Obtener estadísticas de resumen (usando base R)
summary(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## Species
## setosa :50
## versicolor:50
## virginica :50
##
##
##
Obtenga la media y la desviación estándar para la longitud del sépalo
iris %>% pull(Sepal.Length) %>% mean()
## [1] 5.843333
iris %>% pull(Sepal.Length) %>% sd()
## [1] 0.8280661
Los datos con valores faltantes darán como resultado estadísticas de NA. Agregar el parámetro na.rm = TRUE se puede usar en la mayoría de las funciones estadísticas para ignorar los valores faltantes.
mean(c(1, 2, NA, 3, 4, 5))
## [1] NA
mean(c(1, 2, NA, 3, 4, 5), na.rm = TRUE)
## [1] 3
Los valores atípicos suelen ser los valores más pequeños o más grandes de una característica. Para que la media sea más sólida frente a los valores atípicos, podemos recortar el 10 % de las observaciones de cada extremo de la distribución.
iris %>% pull(Sepal.Length) %>% mean()
## [1] 5.843333
iris %>% pull(Sepal.Length) %>% mean(trim = .1)
## [1] 5.808333
La longitud del sépalo no tiene valores atípicos, por lo que la media recortada es casi idéntica.
Para calcular un resumen de un conjunto de características (p. ej., todas las características numéricas), tidyverse proporciona resume_if().
iris %>% summarize_if(is.numeric, mean)
## # A tibble: 1 × 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <dbl> <dbl> <dbl>
## 1 5.84 3.06 3.76 1.20
iris %>% summarize_if(is.numeric, sd)
## # A tibble: 1 × 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <dbl> <dbl> <dbl>
## 1 0.828 0.436 1.77 0.762
iris %>% summarize_if(is.numeric, list(min = min, median = median, max = max))
## # A tibble: 1 × 12
## Sepal.Length_min Sepal.Width_min Petal.Length_min Petal.Width_min
## <dbl> <dbl> <dbl> <dbl>
## 1 4.3 2 1 0.1
## # ℹ 8 more variables: Sepal.Length_median <dbl>, Sepal.Width_median <dbl>,
## # Petal.Length_median <dbl>, Petal.Width_median <dbl>,
## # Sepal.Length_max <dbl>, Sepal.Width_max <dbl>, Petal.Length_max <dbl>,
## # Petal.Width_max <dbl>
La desviación absoluta mediana (MAD) es otra medida de dispersión.
iris %>% summarize_if(is.numeric, mad)
## # A tibble: 1 × 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <dbl> <dbl> <dbl>
## 1 1.04 0.445 1.85 1.04
Podemos usar la característica nominal para formar grupos y luego calcular estadísticas grupales para las características continuas. A menudo usamos promedios grupales para ver si difieren entre grupos.
iris %>% group_by(Species) %>% summarize(across(Sepal.Length, mean))
## # A tibble: 3 × 2
## Species Sepal.Length
## <fct> <dbl>
## 1 setosa 5.01
## 2 versicolor 5.94
## 3 virginica 6.59
iris %>% group_by(Species) %>% summarize_all(mean)
## # A tibble: 3 × 5
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 setosa 5.01 3.43 1.46 0.246
## 2 versicolor 5.94 2.77 4.26 1.33
## 3 virginica 6.59 2.97 5.55 2.03
Vemos que la especie Virginica tiene el promedio más alto de todos, excepto Sepal.Width.
La diferencia estadística entre los grupos se puede probar usando ANOVA (análisis de varianza).
res.aov <- aov(Sepal.Length ~ Species, data = iris)
summary(res.aov)
## Df Sum Sq Mean Sq F value Pr(>F)
## Species 2 63.21 31.606 119.3 <2e-16 ***
## Residuals 147 38.96 0.265
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
TukeyHSD(res.aov)
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = Sepal.Length ~ Species, data = iris)
##
## $Species
## diff lwr upr p adj
## versicolor-setosa 0.930 0.6862273 1.1737727 0
## virginica-setosa 1.582 1.3382273 1.8257727 0
## virginica-versicolor 0.652 0.4082273 0.8957727 0
Podemos contar el número de flores de cada especie.
iris %>% group_by(Species) %>% summarize(n())
## # A tibble: 3 × 2
## Species `n()`
## <fct> <int>
## 1 setosa 50
## 2 versicolor 50
## 3 virginica 50
En base R, esto también se puede hacer usando count(iris$Species).
Para los siguientes ejemplos, discretizamos los datos usando cut.
iris_ord <- iris %>% mutate_if(is.numeric,
function(x) cut(x, 3, labels = c("short", "medium", "long"), ordered = TRUE))
iris_ord
## # A tibble: 150 × 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <ord> <ord> <ord> <ord> <fct>
## 1 short medium short short setosa
## 2 short medium short short setosa
## 3 short medium short short setosa
## 4 short medium short short setosa
## 5 short medium short short setosa
## 6 short long short short setosa
## 7 short medium short short setosa
## 8 short medium short short setosa
## 9 short medium short short setosa
## 10 short medium short short setosa
## # ℹ 140 more rows
summary(iris_ord)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## short :59 short :47 short :50 short :50 setosa :50
## medium:71 medium:88 medium:54 medium:54 versicolor:50
## long :20 long :15 long :46 long :46 virginica :50
La tabulación cruzada se usa para averiguar si dos características discretas están relacionadas.
tbl <- iris_ord %>% select(Sepal.Length, Species) %>% table()
tbl
## Species
## Sepal.Length setosa versicolor virginica
## short 47 11 1
## medium 3 36 32
## long 0 3 17
La tabla contiene el número de filas que contienen la combinación de valores (p. ej., el número de flores con un sépalo corto. La longitud y la especie Setosa es 47). Si algunas celdas tienen recuentos muy grandes y la mayoría de las demás tienen recuentos muy bajos, entonces podría haber una relación. Para los datos del iris, vemos que la especie Setosa tiene principalmente un sépalo corto.Longitud, mientras que Versicolor y Virginica tienen sépalos más largos.
Crear una tabla cruzada con tidyverse es un poco más complicado y utiliza operaciones de pivote y agrupación.
iris_ord %>%
select(Species, Sepal.Length) %>%
### Relationship Between Nominal and Ordinal Features
pivot_longer(cols = Sepal.Length) %>%
group_by(Species, value) %>% count() %>% ungroup() %>%
pivot_wider(names_from = Species, values_from = n)
## # A tibble: 3 × 4
## value setosa versicolor virginica
## <ord> <int> <int> <int>
## 1 short 47 11 1
## 2 medium 3 36 32
## 3 long NA 3 17
Podemos usar una prueba estadística para determinar si existe una relación significativa entre las dos características. La prueba de independencia de chi-cuadrado de Pearson se realiza con la hipótesis nula de que la distribución conjunta de los recuentos de celdas en una tabla de contingencia bidimensional es el producto de los márgenes de fila y columna. La hipótesis nula h0 es la independencia entre filas y columnas.
tbl %>% chisq.test()
##
## Pearson's Chi-squared test
##
## data: .
## X-squared = 111.63, df = 4, p-value < 2.2e-16
El valor p pequeño indica que la hipótesis nula de independencia debe rechazarse. Para recuentos pequeños (células con recuentos <5), la prueba exacta de Fisher es mejor.
fisher.test(tbl)
##
## Fisher's Exact Test for Count Data
##
## data: tbl
## p-value < 2.2e-16
## alternative hypothesis: two.sided
Los cuantiles son puntos de corte que dividen el rango de una distribución de probabilidad en intervalos continuos con igual probabilidad. Por ejemplo, la mediana es el cuantil empírico del 50 % que divide las observaciones en que el 50 % de las observaciones son más pequeñas que la mediana y el otro 50 % son más grandes que la mediana.
Por defecto se calculan los cuartiles. El 25 % normalmente se llama Q1, el 50 % se llama Q2 o la mediana y el 75 % se llama Q3.
iris %>% pull(Petal.Length) %>% quantile()
## 0% 25% 50% 75% 100%
## 1.00 1.60 4.35 5.10 6.90
El rango intercuartílico es una medida de variabilidad que es robusta frente a valores atípicos. Se define la longitud Q3 - Q2 que cubre el 50% de los datos en el medio.
iris %>% summarize(IQR = quantile(Petal.Length, probs = 0.75) - quantile(Petal.Length, probs = 0.25))
## # A tibble: 1 × 1
## IQR
## <dbl>
## 1 3.5
Los histogramas muestran la distribución de una única característica continua.
ggplot(iris, aes(Petal.Width)) + geom_histogram(bins = 20)
Los diagramas de caja se utilizan para comparar la distribución de una característica entre diferentes grupos. La línea horizontal en el medio de las cajas son las medianas de los grupos, las cajas abarcan el rango intercuartílico. Los bigotes (líneas verticales) abarcan típicamente 1,4 veces el rango intercuartílico. Los puntos que quedan fuera de ese rango suelen ser valores atípicos que se muestran como puntos.
ggplot(iris, aes(Species, Sepal.Length)) +
geom_boxplot()
Para comparar la distribución de las cuatro características utilizando un diagrama de caja ggplot, primero tenemos que transformar los datos en formato largo (es decir, todos los valores de características se combinan en una sola columna).
library(tidyr)
iris_long <- iris %>% mutate(id = row_number()) %>% pivot_longer(1:4)
ggplot(iris_long, aes(name, value)) +
geom_boxplot() +
labs(y = "Original value")
Esta visualización solo es útil si todas las características tienen aproximadamente el mismo rango. Los datos se pueden escalar primero para comparar las distribuciones.
library(tidyr)
iris_long_scaled <- iris %>% scale_numeric() %>% mutate(id = row_number()) %>% pivot_longer(1:4)
ggplot(iris_long_scaled, aes(name, value)) +
geom_boxplot() +
labs(y = "Scaled value")
Los diagramas de dispersión muestran la relación entre dos características continuas.
ggplot(iris, aes(x = Petal.Length, y = Petal.Width, color = Species)) +
geom_point()
Una matriz de diagramas de dispersión muestra la relación entre varias características
library("GGally")
ggpairs(iris, aes(color = Species))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
La visualización de matriz muestra los valores de la matriz mediante una escala de colores.
iris_matrix <- iris %>% select(-Species) %>% as.matrix()
Necesitamos el formato largo para tidyverse.
iris_long <- as_tibble(iris_matrix) %>% mutate(id = row_number()) %>% pivot_longer(1:4)
head(iris_long)
## # A tibble: 6 × 3
## id name value
## <int> <chr> <dbl>
## 1 1 Sepal.Length 5.1
## 2 1 Sepal.Width 3.5
## 3 1 Petal.Length 1.4
## 4 1 Petal.Width 0.2
## 5 2 Sepal.Length 4.9
## 6 2 Sepal.Width 3
ggplot(iris_long,
aes(x = name, y = id, fill = value)) + geom_tile()
Los valores más pequeños son más oscuros. La seriación de paquetes proporciona una función de trazado más simple.
library(seriation)
## Registered S3 methods overwritten by 'registry':
## method from
## print.registry_field proxy
## print.registry_entry proxy
##
## Attaching package: 'seriation'
## The following object is masked from 'package:lattice':
##
## panel.lines
ggpimage(iris_matrix, prop = FALSE)
Podemos escalar las características a puntajes z para que sean más comparables.
iris_scaled <- scale(iris_matrix)
ggpimage(iris_scaled, prop = FALSE)
Esto revela bloques rojos y azules. Cada fila es una flor y las flores en el conjunto de datos de Iris están ordenadas por especies. Los bloques azules para las 50 flores superiores muestran que estas flores son más pequeñas que el promedio para todas menos Sepal.Width y los bloques rojos muestran que las 50 flores inferiores son más grandes para la mayoría de las características.
A menudo, reordenar las matrices de datos ayuda con la visualización. Una técnica de reordenamiento se llama seriación. Ir reordena filas y columnas para colocar más puntos similares más juntos.
ggpimage(iris_scaled, order = seriate(iris_scaled), prop = FALSE)
Vemos que las filas (flores) están organizadas de muy azul a muy rojo y las características se reordenan para mover Sepal.Width completamente hacia la derecha porque es muy diferente de las otras características.
Una matriz de correlación contiene la correlación entre características.
cm1 <- iris %>% select(-Species) %>% as.matrix %>% cor()
cm1
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Sepal.Length 1.0000000 -0.1175698 0.8717538 0.8179411
## Sepal.Width -0.1175698 1.0000000 -0.4284401 -0.3661259
## Petal.Length 0.8717538 -0.4284401 1.0000000 0.9628654
## Petal.Width 0.8179411 -0.3661259 0.9628654 1.0000000
El paquete ggcorrplot proporciona una visualización de matrices de correlación.
library(ggcorrplot)
ggcorrplot(cm1)
La seriación de paquetes proporciona una versión reordenada de este gráfico mediante un mapa de calor.
gghmap(cm1, prop = TRUE)
Las correlaciones también se pueden calcular entre objetos mediante la transposición de la matriz de datos.
cm2 <- iris %>% select(-Species) %>% as.matrix() %>% t() %>% cor()
ggcorrplot(cm2)
Las correlaciones de objeto a objeto se pueden utilizar como una medida de similitud. Los bloques de color rojo oscuro indican diferentes especies.
Los gráficos de coordenadas paralelas pueden visualizar varias características en un solo gráfico. Las líneas conectan los valores de cada objeto (flor).
library(GGally)
ggparcoord(iris, columns = 1:4, groupColumn = 5)
La gráfica se puede mejorar reordenando las variables para colocar características correlacionadas una al lado de la otra.
o <- seriate(as.dist(1-cor(iris[,1:4])), method = "BBURCG")
get_order(o)
## Petal.Length Petal.Width Sepal.Length Sepal.Width
## 3 4 1 2
ggparcoord(iris, columns = get_order(o), groupColumn = 5)